package com.gxkj.drm.sdk.server;

import com.alibaba.fastjson.JSONObject;
import com.gxkj.drm.entitys.ResourceManage;
import com.gxkj.drm.sdk.annotation.ManagedAttribute;
import com.gxkj.drm.sdk.annotation.ManagedResource;
import com.gxkj.drm.uitls.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.jmx.export.MBeanExporter;
import org.springframework.jmx.support.ConnectorServerFactoryBean;
import org.springframework.remoting.rmi.RmiRegistryFactoryBean;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.management.MalformedObjectNameException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by sxf on 2017/6/26.
 */
public class DrmServer implements ApplicationListener<ContextRefreshedEvent> {

    private String[] scanPackages;

    private String cluster;

    private Map<String, Object> beans;
    //drm系统的域名
    private String domainUrl;

    private static final String DOMAIN = "http://%s/resource_manage/push_resource";

    private static final String DRM_PORT = DrmEnv.getDrmPort();

    private static final String DRM_AUTH_DIR = DrmEnv.getDrmAuthDir();

    private static final String JMX_PASSWORD_FILE = DRM_AUTH_DIR + "/jmxremote.password";

    private static final String JMX_ACCESS_FILE = DRM_AUTH_DIR + "/jmxremote.access";

    private static final String JMX_SERVICE_URL = "service:jmx:rmi:///jndi/rmi://127.0.0.1:" + DRM_PORT + "/server";

    private static final Logger logger = LoggerFactory.getLogger(DrmServer.class);

    private static final String NOT_PUSH = "NOT_PUSH";

    /**
     * 需要等spring 都加载完成在执行
     */
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (event.getApplicationContext().getParent() == null) {//root application context 没有parent，他就是老大.不加这个判断会执行2次
            //需要执行的逻辑代码，当spring容器初始化完成后就会执行该方法。
            this.initResourceInfo();
        }
    }

    public void initResourceInfo() {
        try {
            List<ResourceManage> resourceList = new ArrayList<ResourceManage>();

            //注册MBean
            for (Class<?> clz : ScanPackageUtil.loadMBClasses(scanPackages)) {
                List<ResourceManage> list = getManangAttributeList(clz);
                if (!CollectionUtils.isEmpty(list)) {
                    resourceList.addAll(list);
                }
            }

            if (!CollectionUtils.isEmpty(resourceList)) {
                JSONObject json = new JSONObject();
                json.put("cluster", this.cluster);
                json.put("ip", String.format("%s:%s", DrmEnv.getDrmHostName(), DRM_PORT));//（目标本机rmi）IP和端口
                json.put("data", resourceList);

                Map<String, Object> params = new HashMap<String, Object>();
                params.put("push_data", json);
                HttpUtil.getIntance().post(String.format(DOMAIN, this.domainUrl), params);
                logger.info("resource Manage push success");
            }
        } catch (Exception e) {
            logger.error("resource Manage push fail", e);
        }
    }



    private static List<ResourceManage> getManangAttributeList(Class<?> clz) {
        List<ResourceManage> resourceList = new ArrayList<ResourceManage>();
        ManagedAttribute managedAttribute;
        for (Field field : clz.getDeclaredFields()) {
            managedAttribute = field.getAnnotation(ManagedAttribute.class);
            if (managedAttribute != null) {
                ResourceManage rm = new ResourceManage();
                String objectNameDesc = clz.getAnnotation(ManagedResource.class).objectNameDesc();
                if (StringUtils.isEmpty(objectNameDesc)) {
                    objectNameDesc = ObjectNameUtil.getObjectNameStr(clz);
                }
                if (!managedAttribute.initEnable()) {
                    rm.setAttributeValue(NOT_PUSH);
                }
                rm.setResourcePath(objectNameDesc);
                rm.setAttribute(getUpperCase(field.getName()));
                resourceList.add(rm);
            }
        }

        return resourceList;
    }

    private static String getUpperCase(String attributeName) {
        StringBuilder sb = new StringBuilder(attributeName);
        sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));

        return sb.toString();
    }

    public void setScanPackages(String[] scanPackages) {
        this.scanPackages = scanPackages;
    }

    public void setCluster(String cluster) {
        this.cluster = cluster;
    }

    public void setBeans(Map<String, Object> beans) {
        this.beans = beans;
    }

    public void setDomainUrl(String domainUrl) {
        this.domainUrl = domainUrl;
    }

    @Bean
    public MBeanExporter mBeanExporter() {
        MBeanExporter mBeanExporter = new MBeanExporter();
        mBeanExporter.setBeans(this.beans);

        return mBeanExporter;
    }

    @Bean
    public RmiRegistryFactoryBean registry() {
        RmiRegistryFactoryBean rmiRegistryFactoryBean = new RmiRegistryFactoryBean();
        rmiRegistryFactoryBean.setPort(Integer.parseInt(DRM_PORT));
        return rmiRegistryFactoryBean;
    }

    @Bean
    @DependsOn("registry")
    public ConnectorServerFactoryBean connectorServer() throws MalformedObjectNameException {
        ConnectorServerFactoryBean connectorServerFactoryBean = new ConnectorServerFactoryBean();
        Map<String, Object> environment = new HashMap<>();
        connectorServerFactoryBean.setObjectName("connector:name=rmi");
        connectorServerFactoryBean.setServiceUrl(JMX_SERVICE_URL);
        environment.put("jmx.remote.x.password.file", JMX_PASSWORD_FILE);
        environment.put("jmx.remote.x.access.file", JMX_ACCESS_FILE);
        connectorServerFactoryBean.setEnvironmentMap(environment);

        return connectorServerFactoryBean;
    }
}